﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Collections;
using System.Reflection;

using System.Globalization;

namespace Idlesoft.Utils
{
	public static class Converters
	{
		public static bool IsEnumerable(Type type)
		{
			bool isEnumerable = false;
			if (type.IsArray)
				isEnumerable = true;
			else if (type.IsGenericType)
			{
				if (type.Equals(typeof(Nullable<>)))
					isEnumerable = true;
				else if (type.Equals(typeof(List<>)))
					isEnumerable = true;
			}
			return isEnumerable;
		}

		public static TypeConverter GetCoverter(Type type)
		{
			TypeConverter converter = null;
			ConstructorInfo ctor = null;
			Type[] types = new Type[] { type.GetElementType() };

			if (type.IsArray)
			{
				ctor = typeof(ArrayConverter<>).MakeGenericType(types).GetConstructor(Type.EmptyTypes);
				converter = ctor.Invoke(null) as TypeConverter;
			}
			else if (type.IsGenericType)
			{
				if (type.Equals(typeof(Nullable<>)))
				{
					converter = new NullableConverter(type);
				}
				else if (type.Equals(typeof(List<>)))
				{
					ctor = typeof(ListConverter<>).MakeGenericType(types).GetConstructor(Type.EmptyTypes);
					converter = ctor.Invoke(null) as TypeConverter;
				}
				else if (type.Equals(typeof(Dictionary<,>)))
				{
					ctor = typeof(DictionaryConverter<,>).MakeGenericType(types).GetConstructor(Type.EmptyTypes);
					converter = ctor.Invoke(null) as TypeConverter;
				}
			}
			else
				converter = TypeDescriptor.GetConverter(type);

			return converter;
		}


	}
	public class ArrayConverter<T> : TypeConverter
	{

		public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
		{
			if (sourceType == typeof(string))
				return true;
			return base.CanConvertFrom(context, sourceType);
		}
		public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
		{
			return base.CanConvertTo(context, destinationType);
		}
		public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
		{
			//if (value is string[])
			//{
			//    TypeConverter converter = Common.GetConverter(typeof(T));
			//    return (value as string[]).Select(v => (T)converter.ConvertFrom(v)).ToArray();
			//}
			//else if (value is string)
			//{
			//    TypeConverter converter = Common.GetConverter(typeof(T));
			//    return new T[] { (T)converter.ConvertFrom(value) };
			//}
			Type type = value.GetType();
			if (type.IsArray)
			{
				Type elem = type.GetElementType();
				if (elem.Equals(typeof(object)))
				{
					TypeConverter converter = Common.GetConverter(typeof(T));
					return (value as IEnumerable).Cast<string>().Select(v => (T)converter.ConvertFrom(v)).ToArray();
				}
				else if (elem.Equals(typeof(string)))
				{
					TypeConverter converter = Common.GetConverter(typeof(T));
					return (value as string[]).Select(v => (T)converter.ConvertFrom(v)).ToArray();
				}
			}
			else if (value is string)
			{
				TypeConverter converter = Common.GetConverter(typeof(T));
				return new T[] { (T)converter.ConvertFrom(value) };
			}
			return base.ConvertFrom(context, culture, value);
		}
		public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
		{
			object result = null;

			TypeCode code = Type.GetTypeCode(destinationType);
			if (code == TypeCode.String)
			{
				object[] values = null;
				if (value.GetType().IsArray)
					values = value as object[];
				else
					values = new object[] { value };

				result = values.Flatten("{ ", ", ", " }");
			}
			else
				base.ConvertTo(context, culture, value, destinationType);
			return result;
		}
	}
	public class ListConverter<T> : ArrayConverter<T>
	{
		public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
		{
			if (sourceType == typeof(string))
				return true;
			return base.CanConvertFrom(context, sourceType);
		}
		public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
		{
			return base.CanConvertTo(context, destinationType);
		}
		public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
		{
			List<T> result = null;
			object array = base.ConvertFrom(context, culture, value);
			if (array != null)
				result = new List<T>(array as IEnumerable<T>);
			return result;
		}
		public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
		{
			object result = null;

			TypeCode code = Type.GetTypeCode(destinationType);
			if (code == TypeCode.String)
			{
				if (value.GetType().IsGenericType)
				{
					Guid guid = value.GetType().GUID;
					if ("5af00c2e-048b-3ab3-8ccd-548134771d38" != guid.ToString())
					{
						List<string> list = value as List<string>;
						result = list.Flatten("{ ", ", ", " }");
					}
				}
			}
			else
				base.ConvertTo(context, culture, value, destinationType);
			return result;
		}
	}
	public class DictionaryConverter<K, V> : TypeConverter
	{
		public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
		{
			if (sourceType == typeof(string))
				return true;
			return base.CanConvertFrom(context, sourceType);
		}
		public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
		{
			return base.CanConvertTo(context, destinationType);
		}
		public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
		{
			string text = value as string;
			if (text != null)
			{
				try
				{
					throw new NotImplementedException("dictionary support to come");
				}
				catch { }
				throw new ArgumentException("The arguments were not valid in DictionaryConverter.ConvertFrom");
			}

			return base.ConvertFrom(context, culture, value);
		}
	}
}
